// Copyright 2021 Apulis Technology Inc. All rights reserved.

package dto

import (
	"net/http"

	"apedge/pkg/common"
	"apedge/pkg/loggers"
	proto "apedge/pkg/protocol"

	"github.com/gin-gonic/gin"
)

var logger = loggers.LogInstance()

type HandlerFunc func(c *gin.Context) error

type APIErrorResp struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}

type APISuccessResp struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

type APIIPCResp struct {
	Status string      `json:"status"`
	Msg    string      `json:"msg"`
	Data   interface{} `json:"data"`
}

func Wrapper(handler HandlerFunc) func(c *gin.Context) {
	return func(c *gin.Context) {
		err := handler(c)
		if err != nil {
			logger.Error(err.Error())
		}
	}
}

//////////////// Success Message //////////////////
func SuccessResp(c *gin.Context, content interface{}) error {
	res := APISuccessResp{
		Code: common.SUCCESS_CODE,
		Msg:  "OK",
		Data: content,
	}
	c.JSON(http.StatusOK, res)
	return nil
}

//IPC
func SuccessIPCResp(c *gin.Context, content interface{}) error {
	res := APIIPCResp{
		Status: "200",
		Msg:    "OK",
		Data:   content,
	}
	c.JSON(http.StatusOK, res)
	return nil
}
func FailedIPCResp(c *gin.Context, status, msg string) error {

	res := APIIPCResp{
		Status: status,
		Msg:    msg,
	}
	c.JSON(http.StatusOK, res)
	return nil
}

func NoReqSuccessResp(c *gin.Context, content interface{}) error {
	res := APISuccessResp{
		Code: common.SUCCESS_CODE,
		Msg:  "OK",
		Data: content,
	}
	rsp := proto.NewRawMessage()
	rsp.FillBody(res)
	c.JSON(http.StatusOK, rsp)
	return nil
}

//////////////// Error Message //////////////////
func (e *APIErrorResp) Error() string {
	return e.Msg
}

func HandleNotFound(c *gin.Context) {
	var req proto.Message

	// no need to handle err here
	_ = c.ShouldBindJSON(&req)
	rsp := ErrorResp(common.NOT_FOUND_ERROR_CODE, http.StatusText(http.StatusNotFound))
	c.JSON(http.StatusNotFound, rsp)
}

func HandleProb(c *gin.Context) {
	c.JSON(http.StatusOK, "OK")
}

func ErrorNoBodyResp(code int, msg string) *APIErrorResp {
	errMsg := &APIErrorResp{
		Code: code,
		Msg:  msg,
	}

	return errMsg
}

func ErrorResp(code int, msg string) *APIErrorResp {
	errMsg := &APIErrorResp{
		Code: code,
		Msg:  msg,
	}
	return errMsg
}

func ErrorIPCResp(code int, msg string) *APIErrorResp {
	errMsg := &APIErrorResp{
		Code: code,
		Msg:  msg,
	}
	return errMsg
}

func NoBodyUnAuthorizedError(msg string) *APIErrorResp {
	rsp := ErrorNoBodyResp(common.AUTH_ERROR_CODE, msg)
	return rsp
}

func UnAuthorizedError(c *gin.Context, req *proto.Message, msg string) *APIErrorResp {
	err := ErrorResp(common.AUTH_ERROR_CODE, msg)
	c.JSON(http.StatusUnauthorized, err)
	return err
}

func ServerError(c *gin.Context) *APIErrorResp {
	err := ErrorResp(common.SERVER_ERROR_CODE, http.StatusText(http.StatusInternalServerError))
	c.JSON(http.StatusInternalServerError, err)
	return err
}

func NotFoundError(c *gin.Context, req *proto.Message) *APIErrorResp {
	err := ErrorResp(common.NOT_FOUND_ERROR_CODE, http.StatusText(http.StatusNotFound))
	c.JSON(http.StatusNotFound, err)
	return err
}

func UnknownError(c *gin.Context, req *proto.Message, msg string) *APIErrorResp {
	err := ErrorResp(common.UNKNOWN_ERROR_CODE, msg)
	c.JSON(http.StatusForbidden, err)
	return err
}

func ParameterError(c *gin.Context, msg string) *APIErrorResp {
	err := ErrorResp(common.PARAMETER_ERROR_CODE, msg)
	c.JSON(http.StatusBadRequest, err)
	return err
}

func AppError(c *gin.Context, errCode int, msg string) *APIErrorResp {
	err := ErrorResp(errCode, msg)
	c.JSON(http.StatusBadRequest, err)
	return err
}

func AppIPCError(c *gin.Context, errCode int, msg string) *APIErrorResp {
	err := ErrorIPCResp(errCode, msg)
	c.JSON(http.StatusBadRequest, err)
	return err
}

func NoReqAppError(c *gin.Context, msg string) *APIErrorResp {
	err := ErrorNoBodyResp(common.AUTH_ERROR_CODE, msg)
	c.JSON(http.StatusBadRequest, err)
	return err
}

func ServeError(c *gin.Context, req *proto.Message, errCode int, msg string) *APIErrorResp {
	err := ErrorResp(errCode, msg)
	c.JSON(http.StatusInternalServerError, err)
	return err
}

func ErrorToCodeRsp(c *gin.Context, err error) *APIErrorResp {
	errCode, ok := common.ErrorMap[err]
	if ok {
		return AppError(c, errCode, err.Error())
	}
	return AppError(c, common.APP_ERROR_CODE, err.Error())
}
